﻿using System;
using System.Activities;
using System.Threading;
using CommandRunner.Contract;
using CommandRunner.Core;
using CommandRunner.Model;
using CommandRunner.WCFDataTransport;

namespace CommandRunner.WorkflowActivity
{
    public class ExecuteRemoteCommand : CodeActivity
    {
        [RequiredArgument]
        public InArgument<string> Command { get; set; }

        [RequiredArgument]
        public InArgument<string> Server { get; set; }

        public InArgument<bool?> InteractiveWindow { get; set; }

        public InArgument<bool?> MonitorSuccess { get; set; }

        public InArgument<int?> Port { get; set; }

        public InArgument<string> WorkingDirectory { get; set; }

        public OutArgument<CommandExecutionStatus> ExecutionStatus { get; set; }

        public OutArgument<string> CommandOutput { get; set; }

        protected override void Execute(CodeActivityContext context)
        {
            string command = Command.Get(context);
            string server = Server.Get(context);
            bool interactiveWindow = InteractiveWindow.Get(context).HasValue && InteractiveWindow.Get(context).Value;
            bool monitorSuccess = MonitorSuccess.Get(context).HasValue && MonitorSuccess.Get(context).Value;
            int? port = Port.Get(context);
            string workingDirectory = WorkingDirectory.Get(context);

            Runner runner = SetupSingleCommandRunner(command, server, port, workingDirectory, interactiveWindow, monitorSuccess);

            bool resultReturned = false;

            runner.CommandCompleted += result => { CommandOutput.Set(context, result.Output); resultReturned = true; };
            runner.CommandFailed += result => { CommandOutput.Set(context, result.Output); resultReturned = true; };

            ExecutionStatus.Set(context, runner.RunCommands());

            DateTime start = DateTime.UtcNow;
            while (!resultReturned)
            {
                Thread.Sleep(1000);
                if ((DateTime.UtcNow - start) > TimeSpan.FromMinutes(5))
                    throw new TimeoutException("The timeout for waiting on Command Runner events to fire has expired");
            }
        }

        private Runner SetupSingleCommandRunner(string command, string server, Nullable<int> port, string workingDirectory, bool interactive, bool monitorSuccess)
        {
            ICommandRunnerConfigurationManager configManager = new ConfigurationManagerSingleCommand(command, server, port, workingDirectory, interactive, monitorSuccess);
            ICommandRunnerClientDataTransport dataTransport = new CommandRunnerClient();
            Runner commandRunner = new Runner(configManager, dataTransport);
            return commandRunner;
        }
    }
}
